注意:大家按照顺序编写,不能在第 1 行编写。而且不能开车
说的是客户端版本吗?客服端? 一般都是服务端会向下兼容,或者客户端到一定低版本后,会自动退出,强制用户升级,另外多版本问题,可以放在 bff 层来做,会更合适一些。BFF 本来就会对业务做纵向拆分,b 站听毛老师说是分成了三个我记得。
闭环一般都是通用服务下沉。 服务间的调用跟业务相关,一般都是 rpc 调用。DAG 框架我没用过,同事说很难用,估计封装的不好吧。。。 openresty 链路追踪
gw 负责的是下游服务,统一收敛的公共能力,比如你提到的鉴权,防水墙(安全问题),缓存,频控等等。公共能力如果每次变更,下游所有服务都需要在发布一般,所以才有了 gw 这一层。 并且这一层可以各个接口的监控,大盘的整体健康度等。所以是很有必要的。BFF 你可以没有很好的理解,一般公司可以不会有这一层。 因为 b 站业务终端场景复杂,tv、mac、iphone、aphone、web 等等。为了适配多端场景,根据不同业务抽象出来这一层。放在后台做,目的就是一些简单的变更等,都不需要终端发版等。也方便下游不需要为了适配,而编写不同的代码。
两个是不同概念,毛老师后面会讲。 内部服务调用,你想问的是会扩散的问题吗。
没有状态,服务之间一般都是没有状态的,一般都是存储才会涉及到有无状态。 网关一般不会挂的,1 代码也有各个单测,测试用例等通过一些手段来保证代码等质量
2 部署发布阶段会有灰度等策略。并且服务机房间就是本来就是集群。如果因为过载等会有监控,限流,熔断等手段来保证,而且一般都是下游业务相关,网关不容易挂,再有如果机房及时关了,一般网关都会有跨机房容灾的。
可以看下 9 回答,是的,bff 一般都是数据整合。 事务一致性,毛老师应该也会说。
因为下游服务可能会需要用到这些信息,方便下游。具体得看业务场景,也不一定要这么设计。
--A: 基础服务,如消息队列服务,缓存服务等功能服务。
-- GraphQL 和 CQRS 没有关系,compose 是 GraphQL 的应用场景
--grpc 提供对外的端口提供服务即可,注意安全鉴权这块
grpc的"传输介质"是http2, 只要通信的两端支持http2协议,就可以使用grpc,和内网,公网没啥区别。
-- 第一个问题,数据组装这块要按照具体情况来定,如果涉及到核心业务直接抛出异常错误码,如果不是核心业务返回空数据,前端兼容数据展示。数据裁剪得看客户端或者前端的数据格式来定,因为业务不一样还是定义实体来区分比较好。第二个问题,可以考虑并行方式用 id 去调用后端原子服务。
-- 这样理解对自己严格对他人宽容,自己在发送数据时按照既定的格式或者规范进行格式化,而在接收方时为了保证自身服务的健壮性,在解析这些数据时兼容更多的版本格式或者可能的数据格式,涉及到多余的字段就可以忽略
-- BFF 上写调用接口的代码就是搬砖的工作,BFF也支持裸透传,哈哈哈
如果从consul拉取的服务端的ip列表和之前的不一样,是一定要修改nginx配置文件,然后 reload的(nginx -s reload)
官方的整体应用架构图如下:
若有其他细节疑问可私聊我沟通。
问的同学是运维安全向的吗,是指的容器内操作的审计,还是容器镜像拉取推送呢。
大体整体如下:
(1)容器内操作的审计:可以走传统的堡垒机方案,逻辑是在连接容器时先在堡垒机运行录制程序或脚本,然后对命令进行记录或筛选。
(2)容器镜像拉取推送:需要实现代理,在仓库和用户间使用代理对请求进行过滤,案例的话可以具体实现可以参照harbor的代理模块。
服务化后后端服务基本切割的比较原子级,大多无法直接应对业务端的访问。而 BFF 就承担了业务聚合层的功能,需要针对不同的端进行业务数据裁剪、聚合和再组。
需要上下文,单纯看问题没法确定,麻烦私聊我沟通。
可以看看 https://github.com/bilibili/kratos,自己多搭建几个服务,实际跑一下。如果对实践项目有疑问,可以看看我出的 《Go 语言编程之旅》的第三章有相关的实践内容。
已私聊回答你。
一般都需要。go在高并发方面有优势,而nginx在性能,安全,缓存,静态文件处理,稳定性等方面都是go比不过的。并不是用go一定写出来,而且市面上已经有nginx把这一部分做的非常好了,其他人就没有十足的动力重复造轮子了。
一般有专门的一个 git repo 进行管理,进一步升级,可以集成在服务接入平台上来进行管理。
db 之间不应该互相共享数据,尽量用 id 来进行互相关联。部分互联网.应用采用反范式设计,会做一些冗余,例如淘宝的订单中的地址信息等。
可插拔是一种架构上的概念,如果你的功能是依赖于接口而不是具体实现,那么你就可以在不修改业务逻辑的情况下更换底层任意实现。
例如获取用户信息,在 request 中可以传 user_id_list:[1,23,323, 2121],server 端同时返回多条用户信息。db 查询可以用 where user_id in () 来实现
可以的话尽量避免多层调用,因为这样容易导致级联失败,迫不得已的情况下,可以要求你的对接方提供一定程度的数据拼装服务。公共返回值这个在说啥没看懂,是说统一的错误码么?trace 信息在现在的 rpc 中一般放在保留字段里,例如 thrift 的第 0 个字段。
----强一致用分布式事务,不需要强一致可以用 CQRS 之类的方案实现最终一致
---- 这就需要实践了,比如如果有个好机会去独立设计一个项目的架构,那么就可以思考一些技术能不能引进在架构中,调研的过程也是学习的过程。
----可以通过 BFF 层来做客户端区分,业务层可以按自己的方式提供数据接口给到 BFF,BFF 层根据不同客户端的需要进行数据处理,然后根据不同的客户端输出它们的数据。
---- 如果每个服务要使用自己的独立的数据库的话也要考虑大数据量,数据冷热分离的问题,这个和实际业务场景相关。
--- 比如前端需要各种门店的数据,但是每个门店在 web 端和 mobile 端的展示方式略有不同,假设 web 端不需要门店标签信息,而 mobile 端需要门店标签信息,这个就可以放在 BFF 中进行区分,而后端 API 不需要区分请求是谁发给自己的。
---按照 2PC 的定义,多个服务就是需要多个服务作为参与者,在协调者的协调下同时 commit 或者 fallback,这个自己实现肯定是比较复杂的,可以考虑一些开源的组件。
解:tcc,seata
解:
柠檬:组件的业务价值是首要性的,如果现有技术体系很好的满足了业务要求,且开发效率也很高,没必要非要切换。一般来说由下到上的推进是比较难的,从上往下的推进会简单很多。
不管如何推进,要明白为什么要替换,有什么收益,要熟悉其优点/缺点/坑点,熟悉其性能,适用场景。做业务适配,效率工具,整理教程等。
先从小的点做起, 新技术虽然炫酷,但也包含着不稳定性以及不好把握,不上线的话,不知道有什么问题。从新服务,非面向用户的后台服务,非核心服务逐渐推进,出问题的话,也不会影响线上,有足够的时间排查积累。
目前看课程安排没有
柠檬: 这种架构看应用场景。状态会存在短暂不一致,但是在可允许范围。
1.稿件状态有限,且变更不会很频繁。
2.实际应用中给别人看的信息,不一致时间窗口小于 2s,基本不会感知到。如果是用户自己看,可以读原数据。
3.当然实际场景会比 ppt 中描述的复杂,除了这一套架构外, 还需要考虑丢消息的问题,是否需要进行一致性校验,全同步等。
柠檬强答:这块我了解不多,我们是自己封装的业务接入层。
graphql 据我了解大公司后端用的不多。
柠檬:服务之间是可以相互调用的,非要乱调的话,也没法硬性阻止,调用需要遵守一定的原则,整洁架构之道这本书有说明。
无依赖环原则:调用关系不应该成环。
稳定依赖原则:依赖必须指向更稳定的方向。
稳定抽象原则:一个组件的抽象化程度应该与其稳定性保持一致。
这些是服务之间调用时需要考虑的原则。比如支付中心就不应该调用业务活动,基础数据就不应该调用首页服务等,越是基础的服务,其依赖应该越少。
架构需要经常进行梳理,排查不合理的地方。比如人工梳理调用图,梳理 trace 图。
柠檬: mq 不能叫服务调用,是一种解耦合,异步的方式,服务发出 mq 信息后,就不再关注了,接收者可以有很多。rpc 是强依赖,同步的方式。
大部分业务逻辑直接用调用 rpc,比如我先调 A, 再调 B, 调 C 等。
mq 一般用在异步场景,解耦, 削峰等。
1.发出领域事件:比如注册,登录,充值,点赞,评论等关键事件。对这些事件感兴趣的服务可以自己去接收处理,处理不处理,处理是否快慢,都不会影响核心服务。
2.异步削峰:可以看作是同步 rpc 的一种降级方案,用于匹配快慢系统。比如活动领券,一般业务服务性能可以很高,但是发券服务要操作 db,有很多校验,甚至需要匹配第三方厂商,一般性能会比较低。高峰时直接发券会打垮发券服务,所以先告诉用户请求成功,发券会稍后到账,接收消息进行匀速的发券处理。
3.消息补偿:同步调 RPC 可能会网络失败,且不可能一直重试,可以将事务的下半部或失败补偿放入消息队列,由另一个服务去保证一致性,参见分布式一致性中的本地消息表和事务消息。
柠檬:不会走面向外网的那种网关,这个问题需要分情况。
网关的定义是什么:不同网络之间的转换的设备。一般网关用于不同系统的边界,做协议转换 / 统一入口 / 安全校验等。
下半节会讲服务发现 / 负载均衡的模式,有客户端发现,服务之间之间调用,服务端发现,通过中间层服务进行调用,比如内部服务统一通过 url 调用 nginx,nginx 做服务发现,负载等。
但是大部分情况都是用的客户端发现,服务之间 ip:port 直接调用,这样可以减少中心单点问题。
还有种情况如果公司比较大,有不同的大团队,可能你是业务服务需要调用别的团队的支付服务,那么就需要走他们的网关了。
解:LB 层往往是业务无关的,即 LB 层不关注具体的业务场景。而不同的业务限流,会有复杂的规则,例如说依据 CPU 情况,网络负载等进行限流。如果要在 LB 层限流,即意味着 LB 层需要掌握这种信息,这对于 LB 来说负载过于沉重。根源还在于说 LB 这一个环节所具备的信息太过于优先,尤其是四层 LB,基本上就没有什么业务信息了,根本做不来。
但其实,硬要在这层做,并非不可以,只不过 LB 无法做复杂的限流。例如简单的,针对 API 硬标准就是不超过 100/s,那么的确可以在七层 LB 的时候,考虑支持的。只不过收益不高而且又导致 LB 不再是纯粹的 LB,影响 LB 本身的性能。通常 LB 是全局性的,意味着你针对某个 API 的限流的逻辑的开销,会影响到你全局的 LB 的性能。
解:容器编排其实是指自动化容器的部署、管理、扩展。举个例子,使用 k8s 编排容器,那么当某个容器突然死掉,那么 k8s 就会自动启动一个。k8s 是一种声明式的 API,即我们声明我们期望的集群是一个怎样的集群,例如有多少个实例。那么 k8s 就会调度管理容器,达到我们所期望的状态。
解:这个问题可谓是击中了微服务一个老大难的问题。我可以更加深入描述一下这个问题,除了题目本身提到的跨服务 query/join 的问题,还有一个更加可怕的问题,即一条链路上重复调用某个服务多次。例如 A 服务调用 B 服务,而 A 和 B 服务都调用 C 服务,因此在这个过程就会调用两次 C 服务。
从一般的设计上来说,我们会使用聚合服务来完成跨服务的 query 和 join。BFF 也具备同样的性质。
就是我们在专门的领域服务至上构建一个聚合服务,聚合服务来调用下层的领域服务。领域服务来完成数据的组装,而后拼接返回给客户端。
这里面涉及到一个灰色地带的问题。即这种聚合数据的逻辑,我们是否认为是客户端应该 own 的逻辑。如果是,那么放在客户端也是合理的。
无论是聚合服务处理还是客户端处理,都难以避免响应大的问题。但是,就我们实践经验来看,造成性能瓶颈的往往不在 RPC 请求响应的传输过程,所以,这些缺点是可以忍受的。
而从优化的角度来说,我们宁愿提高服务端生成响应的速度,也不愿意为了性能而将业务逻辑放在不合适的地方。
解:api 网关,即 api-gateway。
解:并不能。目前来看,gateway 的很多功能,都是 k8s 的 servic,Ingress 所不支持。比如说熔断,协议转换之类的。
解:目前长链路的测试还是比较复杂的。核心在于,要有一个东西,能够把链路整个串起来。比如说,通常的 tracing 工具,我们会使用 traceId 来追踪。又或者,在链路开端生成一个代表本次请求的唯一 ID,而后使用链路的这个 ID 来追踪整个链路的执行情况。
而还有一个难点在于,长链路的话,需要有一个稳定的测试环境。通常而言我们修改或者开发新功能,不会是整个链路都修改,而是中间某几个环节变更,因此,在测试的时候首先要保证,没有变更的那些环节,是稳定的,能够如预期工作。而后测试的工作就不会因为那些环节出问题卡住。
而后,如果可以的话,应该考虑使用 mock 服务提前进行测试,而不是一直等到全链路都准备好才开始测试。
至于全链路压测,难点在于环境搭建。我们先考虑最简单的读链路压测。读链路压测,因为不涉及数据变更,所以环境可以直接通过生产环境横向扩展完成搭建(加服务器,加服务器!加读库加读库!)。而后,我们需要在请求里面带上一个标记这是压测请求的标志位,在整个链路中间传递。这些请求应该只会被用于支持链路压测的服务器所处理(避免影响正常请求)。
而写请求的链路压测,则复杂得多。难点在于准备数据库。一般而言是使用影子表或者影子库。影子表使用比较简单,但是因为它和正常的表共享一个库,所以天然就会影响正常请求。影子库要好一些,可以规避对正常请求的影响。无论是影子表还是影子库,绕不开的一个问题就是,真实生产环境的数据是极多的,准备这种影子环境,只能考虑将一部分数据导入过来。于是就涉及数据间的一致性。例如你准备用户表,就要将相应的用户的订单数据也弄出来……
此外就是,压测的另外一个难点是构造请求。通常做法是录制流量而后重放。即录制真实用户的流量,而后重放这些请求。这方面有一些合规性的问题,即有些数据,在某些国家的隐私标准之下,是不允许这样重放的。
解:单个 TCP 端口上提供 HTTP/1.1 和 gRPC 接口服务,可以在接口检测 Content-Type 是否是 grpc,检测是否是 http/2,根据不同的协议转发到不同的服务处理
解:数据库的拆分要根据业务来拆一般来说不要跨业务访问库(通过服务接口),分库分表取决于业务要解决的问题,比如单表数据过多造成单表读瓶颈考虑水平分表,单表有大字段考虑垂直分表,单实例写瓶颈考虑分库分实例
解:查询数据库尽量保持简单,不要为了微服务而微服务去拆分库实例给业务造成不必要的操作
解:serverless 是一个比较大的范畴,FAAS/BAAS 都是 serverless 的一种实现,微服务是一种架构主要本质有两点:解藕,分布式
解:有的,具体怎么限流要根据业务场景,一些比较特殊的业务场景需要自己增加限流逻辑
1.以外部服务条件为基准,通过本服务 id 排序查并询数据,查询完之后,通过外本服务键加上本服务条件需要获取本服务数据再进行组装。2 为什么要本服务 id 进行排序呢?主要是因为怕本服务分页时候出问题。
.缓存外部需要查询的数据到本地,但需要考虑数据一致性问题。
https://juejin.cn/post/6908220694929080333
如果进入 bff 节点的流量,经过了网关,那么网关可以进行负载均衡,但首先它要支持这个能力。如果 bff 节点到微服务没有经过网关,那负载均衡就应该是代理来充当负载均衡的角色。
gateway 应该自有一套账号体系,独立于账号服务。因为 gateway 使用账号的主体是服务,而账号服务使用账号主体是人。那就应该就不存在与登陆注册服务交互。
从生产者方面,失败重试。从中间件方面,1.进程监控,2.队列监控,包括消息堆积、消费者存活数量等,从消费者方面,消息幂等。
不是
这种模式比较类似现在说的中台模式,平台服务是有业务属性的能被多条业务线公用的服务。BFF 是纯数据拼装服务,里面没有太重的业务逻辑。业务服务是各个业务线自己的重业务逻辑。
BFF 的出口协议可以随意(你可以说 gRPC 性能好,也可以说 http1.1 更直观好调试)的,按毛老师昨晚讲的在 BFF 前面还套了一个 envoy,怎么方便怎么来。
目前 Go 还是有 GC 和调度,在一些延迟敏感的场景不好用,比如入口网关,或者 dbproxy。个人认为 Go 最擅长的还是在业务模块。或那些对延迟不敏感的基础设施。
可以参考 github 上一些国外公司的做法,比如 dropbox 的 util 库等等。
97.最大限度的容忍冗余数据希望举个例子
99. api 自动化测试提到使用 yapi,我们最近也想做自动化测试,还有相关这类好的工具推荐吗?我下来对比调研下,另外 b 站目前就是实际使用 yapi 来做的吗?
1)如果真的由于这种 panic 而导致的进程退出,该如何排查最终导致 panic 的问题所在呢,毕竟当时引发此 panic 的进程已经退出了,这里可否提供一个简单的 case 呢,真实实战一把排查定位问题的过程
2)平时写代码时,该如何避免这种由于 panic 而导致的进程退出呢
3)有没有这种情况:如果某个场景下真的出现了不知道的异常错误(对于异常处理的代码来说相当于是未知的错误),但也确实成功地捕获到了它,这时是该让进程退出呢?还是忽略掉未知错误呢?
103.毛老师,你好,闭环去做微服务,这个闭环该怎么理解?每个单独的服务独享数据库,那每个服务的数据库,之间的关联关系呢?
104。服务之间通信,应该选 http 还是 rpc,gRPC,什么场景使用 http,什么场景使用 rpc,他们各自的优缺点是什么
跨机器的通信,需要用到网络。在7层网络协议中,一般使用TCP,UDP和TCP之上的http协议。(暂不引入其他的协议)
RCP(远程过程调用)是一种逻辑上的概念,需要借助网络来通信。RCP更加关注调用者和服务提供者,而有意忽略通信协议和消息格式。(而且通信协议和消息格式一般都是可插拔/替换的)
gRCP就是这种思路的一种具体实现。采用的通信协议为HTTP2,消息格式为protocol buffer。
与protocol buffer同级的有json,xml,msgpack,核心就是如何表示消息。
与gRCP同级的有thrift,主要关注消息的发送,接受和传输,依赖TCP或者HTTP。
http无法与RPC直接比较,因为两者是不同的概念。http只负责把消息送到,而RCP更加抽象,涵盖更广。
1)如果业务服务在后面某个版本中需要查询更多的字段信息,而这些信息之前并没有同步过来,此时该如何解决呢?目前能想到的是写个脚本去全量同步过来,还会有更好的解决方案吗
2)如果写脚本同步,这个脚本又该写在哪里呢?提供查询的业务服务中?
3)还有就是读取数据的方式问题,应该不可以直接连对方的 DB 吧,还是让对方提供接口的方式呢?感觉都不太合理.
根据这个老哥的回答:https://zhuanlan.zhihu.com/p/31866490,JWT上下游使用同一个key,如果key泄漏了就没有啥安全性可言。不过我觉得如果JWT的值不太大的话(一般也不会非常大,不会因为加解密增加耗时),加密算法可以使用非对称加密,上游保存公钥(公钥加密),下游注册私钥(私钥解密),也是可行的。一般不这么搞可能觉得没必要,都在一个内网。